/**
 * $Id: InitGatewayConfig.java,v 1.31 2006/09/08 08:16:18 martin Exp $
 *
 * Copyright 2006 Skyinfo, Inc. All Rights Reserved.
 */
package com.haoxi.gateway.common;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.haoxi.gateway.connector.Connector;
import com.haoxi.gateway.messageconvertor.MessageConvertor;

/**
 * TODO
 * 
 * Revision History
 * 
 * 2006-6-6,star.Zhao,created it
 */
public class InitGatewayConfig {
    private static Log log = LogFactory.getLog(InitGatewayConfig.class);
    private static Document document;
    private static String MT_CONNECTOR = "mt";
    private static String MO_MT = "momt";
    private static String MO_CONNECTOR = "mo";

    private static final int SERVER_CONN = 0;
    private static final int NO_SERVER_CONN = 1; // 0,标识是， 1，不是
    private GatewayInfo gatewayInfo = new GatewayInfo();

    private InitGatewayConfig() {
    }

    private static InitGatewayConfig instance = new InitGatewayConfig();

    public static InitGatewayConfig getInstance() {
        return instance;
    }

    /**
     * init Config
     */
    static {
        // 加载配置文件
        InputStream in = InitGatewayConfig.class
                .getResourceAsStream("/gatewayConfig.xml");
        if (in != null) {
            try {
                SAXReader reader = new SAXReader();
                InitGatewayConfig.document = reader.read(in);
                in.close();
            } catch (Exception e) {
                log
                        .fatal(
                                "error occurs during load system Gateway configuration...",
                                e);
                throw new RuntimeException(e.getMessage());
            }
        } else {
            log
                    .fatal("gatewayConfig.xml not found. Please make sure the file is in the classpath");
            throw new RuntimeException(
                    "gatewayConfig.xml not found. Please make sure the file is in the classpath");
        }

        // 解析文件
        // ParseGatewayConfig.parse(ParseGatewayConfig.document);
    }

    /**
     * 解析整个配置文件
     * 
     * @param document
     */
    public void initGatewayConfig() {
        if (null == gatewayInfo) {
            gatewayInfo = new GatewayInfo();
        }
        if (null == document) {
            log.error("the document of gatewayConfig.xml file init failure!");
            throw new RuntimeException(
                    "the document of gatewayConfig.xml file init failure!");
        }

        Node gatewayNode = document.selectSingleNode("//gateway");
        if (null == gatewayNode) {
            log
                    .error("Gateway's configs no config the any Gateway, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the any Gateway, please config it. It must be needed!");
        }

        String gatewayCode = gatewayNode.valueOf("@code");
        gatewayInfo.setGatewayCode(gatewayCode);
        if (null == gatewayCode || gatewayCode.length() == 0) {
            log
                    .error("Gateway's configs no config the Gateway's code, please config it. It must be needed!!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway's code, please config it. It must be needed!!");
        }

        // 当前网关的基本信息
        Node baseInfoNode = gatewayNode.selectSingleNode("//baseInfo");
        parseBaseInfo(baseInfoNode, gatewayCode).convertor(gatewayInfo);

        // 当前网关配置的MessageConvertor
        Node convertorNode = gatewayNode.selectSingleNode("//messageConvert");
        gatewayInfo.setConvertor(parseMessageConvertor(gatewayCode,
                convertorNode));

        // 当前网关的连接
        List connectorNodes = gatewayNode.selectNodes("//connectors/connector");
        if (null == connectorNodes || connectorNodes.size() == 0) {
            log.error("Gateway's configs no config the Gateway(" + gatewayCode
                    + ")'s connector, please config it only one at least!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s connector, please config it only one at least!");
        }
        Iterator it = connectorNodes.iterator();
        while (it.hasNext()) {
            Node connectorNode = (Node) it.next();
            parseConnector(connectorNode, gatewayInfo);
        }
    }
    
    /**
     * 解析整个配置文件for subdsmp
     */
    public void initSubDsmp() {
        if (null == gatewayInfo) {
            gatewayInfo = new GatewayInfo();
        }
        if (null == document) {
            log.error("the document of gatewayConfig.xml file init failure!");
            throw new RuntimeException(
                    "the document of gatewayConfig.xml file init failure!");
        }

        Node gatewayNode = document.selectSingleNode("//gateway");
        if (null == gatewayNode) {
            log
                    .error("Gateway's configs no config the any Gateway, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the any Gateway, please config it. It must be needed!");
        }

        String gatewayCode = gatewayNode.valueOf("@code");
        gatewayInfo.setGatewayCode(gatewayCode);
        if (null == gatewayCode || gatewayCode.length() == 0) {
            log
                    .error("Gateway's configs no config the Gateway's code, please config it. It must be needed!!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway's code, please config it. It must be needed!!");
        }

        // 当前网关的基本信息
        Node baseInfoNode = gatewayNode.selectSingleNode("//baseInfo");
        parseBaseInfo(baseInfoNode, gatewayCode).convertor(gatewayInfo);
    }

    /**
     * 解析网关基本信息
     * 
     * @param node
     * @return
     */
    private BaseInfo parseBaseInfo(Node node, String gatewayCode) {
        BaseInfo baseInfo = new BaseInfo();
        if (null == node) {
            log.error("Gateway's configs no config the Gateway(" + gatewayCode
                    + ")'s baseInfo, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s baseInfo, please config it. It must be needed!");
        }
        Node opNode = node.selectSingleNode("//op");
        if (null == opNode) {
            log.error("Gateway's configs no config the Gateway(" + gatewayCode
                    + ")'s OP info, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s OP info, please config it. It must be needed!");
        }

        // get OP info
        String sOpCode = opNode.valueOf("@code");
        int opCode = 0;
        try {
            opCode = Integer.parseInt(sOpCode);
        } catch (Exception e) {
            log.error("IllegalArgument, op code must be a Integer! OpCode: ["
                    + sOpCode + "]");
            throw new RuntimeException(
                    "IllegalArgument, op code must be a Integer!");
        }
        baseInfo.setOpName(opNode.getText());
        baseInfo.setOpCode(opCode);

        // get spNumber
        Node spNumberNode = node.selectSingleNode("//spnumber");
        if (null == spNumberNode) {
            log.error("Gateway's configs no config the Gateway(" + gatewayCode
                    + ")'s spNumber, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s spNumber, please config it. It must be needed!");
        }
        baseInfo.setSpNumber(spNumberNode.getText());

        Node icpIDNode = node.selectSingleNode("//icp_id");
        if (null == icpIDNode) {
            log.error("Gateway's configs no config the Gateway(" + gatewayCode
                    + ")'s icp_id, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s icp_id, please config it. It must be needed!");
        }
        baseInfo.setIcp_id(icpIDNode.getText());
        baseInfo.setLoginName(icpIDNode.valueOf("@loginname"));
        baseInfo.setPassword(icpIDNode.valueOf("@password"));
        baseInfo.setUnicom_nodeID(icpIDNode.valueOf("@unicomnodeid"));

        Node protocolNode = node.selectSingleNode("//protocol");
        if (null == protocolNode) {
            log
                    .error("Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s protocol info, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s protocol info, please config it. It must be needed!");
        }
        baseInfo.setProtocolName(protocolNode.getText());
        baseInfo.setProtocolVersion(protocolNode.valueOf("@version"));
        Node activeTestContentNode = node
                .selectSingleNode("//activetest_content");
        baseInfo.setActiveTestContent(activeTestContentNode.getText());
        return baseInfo;
    }

    /**
     * 解析配置的消息转换器
     * 
     * @param node
     * @return
     */
    private MessageConvertor parseMessageConvertor(String gatewayCode, Node node) {

        MessageConvertor convertor = null;
        if (null == node) {
            log
                    .error("Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s messageConvert, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s messageConvert, please config it. It must be needed!");
        }
        String name = node.valueOf("@name");
        String classPath = node.valueOf("@class");
        if (null == classPath || classPath.length() == 0) {
            log
                    .error("Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s messageConvert 'class' attribute, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayCode
                            + ")'s messageConvert 'class' attribute, please config it. It must be needed!");
        }

        // 构造消息转换器
        try {
            Class _class = Class.forName(classPath);
            Class partypes[] = new Class[1];
            partypes[0] = String.class;
            Constructor ct = _class.getConstructor(partypes);
            Object arglist[] = new Object[1];
            arglist[0] = gatewayCode;
            convertor = (MessageConvertor) ct.newInstance(arglist);
            log.debug("---- create MessageConvertor[" + name
                    + "] successfully!-------");
        } catch (Exception e) {
            log.error("---- create MessageConvertor[" + name
                    + "] failure!-------");
            throw new RuntimeException("---- create MessageConvertor[" + name
                    + "] failure!-------");
        }
        return convertor;
    }

    /**
     * 解析连接器
     * 
     * @param node
     * @return
     */
    private void parseConnector(Node node, GatewayInfo gatewayInfo) {
        if (null == gatewayInfo || null == gatewayInfo.getGatewayCode()
                || null == gatewayInfo.getIcp_id()
                || null == gatewayInfo.getLoginName()
                || null == gatewayInfo.getPassword()
                || null == gatewayInfo.getProtocolName()) {
            log.error("You must init and parse the gateway basic info!");
            throw new RuntimeException(
                    "No init Or config the gateway basic info!");
        }
        String loginName = gatewayInfo.getLoginName();
        String password = gatewayInfo.getPassword();
        String connectorName = node.valueOf("@name");
        String classPath = node.valueOf("@class");
        if (null == classPath || classPath.length() == 0) {
            log
                    .error("Gateway's configs no config the Gateway("
                            + gatewayInfo.getGatewayCode()
                            + ")'s connector["
                            + connectorName
                            + "] 'class' attribute, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayInfo.getGatewayCode()
                            + ")'s connector["
                            + connectorName
                            + "] 'class' attribute, please config it. It must be needed!");
        }
        String version = node.valueOf("@version");
        if (null == version || "".equals(version.trim())) {
            log.error("Gateway's configs no config the Gateway("
                            + gatewayInfo.getGatewayCode()
                            + ")'s connector["
                            + connectorName
                            + "] 'version' attribute, please config it. It must be needed!");
            throw new RuntimeException(
                    "Gateway's configs no config the Gateway("
                            + gatewayInfo.getGatewayCode()
                            + ")'s connector["
                            + connectorName
                            + "] 'version' attribute, please config it. It must be needed!");
        }

        String sServerConn = node.valueOf("@isServerConn");
        int isServerConn = NO_SERVER_CONN; // 默认不是serverConnector
        if (null != sServerConn && sServerConn.trim().length() > 0) {
            isServerConn = Integer.parseInt(sServerConn.trim());
        }

        String ip = node.valueOf("@ip");
        String port = node.valueOf("@port");
        String checkName = node.valueOf("@checkname");
        String checkPwd = node.valueOf("@checkpwd");
        if (NO_SERVER_CONN == isServerConn) {
            if (null == ip || ip.trim().length() < 7 || null == port
                    || port.trim().length() == 0) {
                log
                        .error("The connector["
                                + connectorName
                                + "] need configs IP and port. It's all needed! Please check gatewayConfig.xml file.");
                throw new RuntimeException("The connector[" + connectorName
                        + "] need configs IP and port. It's all needed!");
            }
        } else if (SERVER_CONN == isServerConn) {
            if (null == port || port.trim().length() == 0) {
                log
                        .error("The connector["
                                + connectorName
                                + "] is ServerConnector, it need configs port! Please check gatewayConfig.xml file.");
                throw new RuntimeException("The connector[" + connectorName
                        + "] is ServerConnector, it need configs port!");
            }

            if (null == checkName || checkName.length() == 0
                    || null == checkPwd) {
                log
                        .error("The connector["
                                + connectorName
                                + "] is ServerConnector, it need configs checkName and checkPwd! Please check gatewayConfig.xml file.");
                throw new RuntimeException(
                        "The connector["
                                + connectorName
                                + "] is ServerConnector, it need configs checkName and checkPwd!");
            } else {
                // ServerConnector's loginName and password is the checkName and
                // checkPwd
                loginName = checkName;
                password = checkPwd;
            }

        } else {
            log.error("Gateway's configs config the Gateway("
                    + gatewayInfo.getGatewayCode() + ")'s connector["
                    + connectorName
                    + "] 'isServerConn' attribute wrong! please Check it.");
            throw new RuntimeException("Gateway's configs config the Gateway("
                    + gatewayInfo.getGatewayCode() + ")'s connector["
                    + connectorName + "] 'isServerConn' attribute wrong!");
        }

        // 构建connector
        Connector connector = null;
        try {
            Class _class = Class.forName(classPath);
            Class partypes[] = new Class[9];
            partypes[0] = String.class;
            partypes[1] = String.class;
            partypes[2] = String.class;
            partypes[3] = String.class;
            partypes[4] = String.class;
            partypes[5] = String.class;
            partypes[6] = Integer.TYPE;
            partypes[7] = Integer.TYPE;
            partypes[8] = String.class;
            Constructor ct = _class.getConstructor(partypes);
            Object arglist[] = new Object[9];
            arglist[0] = gatewayInfo.getGatewayCode();
            arglist[1] = connectorName;
            arglist[2] = gatewayInfo.getIcp_id();
            arglist[3] = loginName;
            arglist[4] = password;
            arglist[5] = ip;
            arglist[6] = new Integer(port);
            arglist[7] = new Integer(version);
            arglist[8] = gatewayInfo.getProtocolName();
            connector = (Connector) ct.newInstance(arglist);
        } catch (Throwable e) {
            log.error("---- create connector failure!-------", e);
            throw new RuntimeException("---- create connector[" + connectorName
                    + "] failure!-------");
        }
        String maxConnCount = node.valueOf("@maxConnCount");
        if (SERVER_CONN == isServerConn) {
            if (null == maxConnCount || maxConnCount.trim().length() == 0) {
                log
                        .error("Gateway's configs no config the Gateway("
                                + gatewayInfo.getGatewayCode()
                                + ")'s 'maxConnCount' attribute, Beacuse it's SGIP ServerConnector. You must be need config it!");
            } else {
                connector.setMaxConnCount(Integer.parseInt(maxConnCount));
            }
        }
        // mo_port, protocolVersion);
        if (isServerConn != SERVER_CONN) {
            // 为空默认为MOMT类型
            String connectorType = node.valueOf("@type");
            if (null == connectorType
                    || connectorType.length() == 0
                    || connectorType
                            .equalsIgnoreCase(InitGatewayConfig.MT_CONNECTOR)) {
                gatewayInfo.addCanSubmitMTConn(connectorName, connector);
                

            } else if (connectorType.equalsIgnoreCase(InitGatewayConfig.MO_MT)) {
                gatewayInfo.addCanSubmitMTConn(connectorName, connector);
                gatewayInfo.addCanReciveDeliverConn(connectorName, connector);

            } else if (connectorType
                    .equalsIgnoreCase(InitGatewayConfig.MO_CONNECTOR)) {
                gatewayInfo.addCanReciveDeliverConn(connectorName, connector);

            } else {
                log.error("Inviad Connector type , Please check it!");
                throw new RuntimeException(
                        "Inviad Connector type , Please check it!");
            }
            gatewayInfo.addClientConnector(connector);
            log.debug("----create ClientConnector:[" + connectorName
                    + "] successfully!-------");
        } else {
            gatewayInfo.addServerConnector(connector);
            log.debug("----Create SGIPDeliverConnector:[" + connectorName
                    + "] successfully!-------");
        }

    }

    class BaseInfo {
        private String opName;
        private int opCode;
        private String icp_id;
        private String unicom_nodeID;
        private String loginName;
        private String password;

        private String protocolName;

        private String activeTestContent;
        private String spNumber;
        private String protocolVersion;

        /**
         * @return Returns the activeTestContent.
         */
        public String getActiveTestContent() {
            return activeTestContent;
        }

        /**
         * @param activeTestContent The activeTestContent to set.
         */
        public void setActiveTestContent(String activeTestContent) {
            this.activeTestContent = activeTestContent;
        }

        /**
         * @param icp_id The icp_id to set.
         */
        public void setIcp_id(String icp_id) {
            this.icp_id = icp_id;
        }

        /**
         * @param opCode The opCode to set.
         */
        public void setOpCode(int opCode) {
            this.opCode = opCode;
        }

        /**
         * @param opName The opName to set.
         */
        public void setOpName(String opName) {
            this.opName = opName;
        }

        /**
         * @param password The password to set.
         */
        public void setPassword(String password) {
            this.password = password;
        }

        /**
         * @param protocolName The protocolName to set.
         */
        public void setProtocolName(String protocolName) {
            this.protocolName = protocolName;
        }
        public void setProtocolVersion(String protocolVersion) {
            this.protocolVersion = protocolVersion;
        }

        /**
         * @param gatewayInfo
         */
        public void convertor(GatewayInfo gatewayInfo) {
            gatewayInfo.setOpName(this.opName);
            gatewayInfo.setOpCode(this.opCode);
            gatewayInfo.setIcp_id(this.icp_id);
            gatewayInfo.setPassword(this.password);
            gatewayInfo.setProtocolName(this.protocolName);
            gatewayInfo.setSpNumber(this.spNumber);
            gatewayInfo.setLoginName(this.loginName);
            gatewayInfo.setUnicom_nodeID(this.unicom_nodeID);
            gatewayInfo.setProtocolVersion(this.protocolVersion);
        }

        /**
         * @param spNumber The spNumber to set.
         */
        public void setSpNumber(String spNumber) {
            this.spNumber = spNumber;
        }

        /**
         * @param loginName The loginName to set.
         */
        public void setLoginName(String loginName) {
            this.loginName = loginName;
        }

        /**
         * @param unicom_nodeID The unicom_nodeID to set.
         */
        public void setUnicom_nodeID(String unicom_nodeID) {
            this.unicom_nodeID = unicom_nodeID;
        }

    }

    /**
     * @return Returns the gatewayInfo.
     */
    public GatewayInfo getGatewayInfo() {
        return gatewayInfo;
    }

    /**
     * test 解析文件
     * 
     * @param args
     */
    public static void main(String[] args) {
        InitGatewayConfig.getInstance().initGatewayConfig();
        GatewayInfo gatewayInfo = InitGatewayConfig.getInstance()
                .getGatewayInfo();
//        InitGatewayConfig.instance.initSubDsmp();
//        GatewayInfo gatewayInfo = InitGatewayConfig.instance.gatewayInfo;
        System.out.println("gatewayInfo : [" + gatewayInfo.getGatewayCode()
                + "]");
        System.out.println("gatewayInfo : ["
                + gatewayInfo.getCanSubmitMTConns().size() + "]");
        System.out.println("gatewayInfo : ["
                + gatewayInfo.getCanReciveDeliverConns().size() + "]");
        System.out.println("gatewayInfo : ["
                + gatewayInfo.getAllConnectors().size() + "]");
        System.out.println("gatewayInfo : [" + gatewayInfo.getGatewayCode()
                + "]");
//            String mobile = "8613922222222";
//             try {
//                System.out.println(new SGIP12MessageConvertor("10011").rmv86(mobile));
//            } catch (Exception e) {
//                // TODO Auto-generated catch block
//                e.printStackTrace();
//            }

    }
}
